#include <functional>
#include <map>

#include "ast_nodes.h"
#include "ast_commands.h"

using namespace ast;
using namespace ast::cmd;

////////////////////////////////////////////////////////
//	Command
////////////////////////////////////////////////////////

namespace {

template<class T>
Command* CreateNewCommand()
{
	return new T;
}

typedef std::function<Command* ()> CreatorFunction;
typedef std::map<Token, CreatorFunction> CreatorMap;

CreatorMap GenerateMap()
{
	CreatorMap map;
	map[Token::ADD] = CreateNewCommand<Add>;
	map[Token::SUB] = CreateNewCommand<Sub>;
	map[Token::NEXT] = CreateNewCommand<Next>;
	map[Token::PREV] = CreateNewCommand<Prev>;
	map[Token::PRINT] = CreateNewCommand<Print>;
	map[Token::SCAN] = CreateNewCommand<Scan>;
	map[Token::IZGN] = CreateNewCommand<Izgn>;
	map[Token::IZGB] = CreateNewCommand<Izgb>;
	return map;
}

Command* CreateCommand(Token token)
{
	static CreatorMap map = GenerateMap();

	auto found = map.find(token);
	if (found != map.end())
		return found->second();
	return nullptr;

}


}

////////////////////////////////////////////////////////
//	Program
////////////////////////////////////////////////////////

void Program::AddASTNode(ASTNode* node)
{
	m_nodes.push_back(node);
}

////////////////////////////////////////////////////////
//	Instruction
////////////////////////////////////////////////////////

Instruction* Instruction::CreateInstruction(Token token)
{
	Instruction* instruction = new Instruction;
	if (!instruction)
		return nullptr;

	Command* command = CreateCommand(token);
	if (!command)
		return nullptr;

	instruction->SetCommand(command);
	return instruction;
}

void Instruction::SetCommand(Command* command)
{
	m_command = command;
}

////////////////////////////////////////////////////////
//	Loop
////////////////////////////////////////////////////////

void Loop::AddASTNode(ASTNode* node)
{
	m_nodes.push_back(node);
}